package it.univaq.mancoosi.injectors.systemconfiguration.managers.ubuntu;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.util.EcoreUtil;

import it.univaq.mancoosi.injectors.systemconfiguration.managers.BootManager;
import it.univaq.mancoosi.injectors.systemconfiguration.managers.ModuleCacheManager;
import it.univaq.mancoosi.injectors.systemconfiguration.utils.ProcessCommand;
import it.univaq.mancoosi.mancoosimm.Alternative;
import it.univaq.mancoosi.mancoosimm.BootScript;
import it.univaq.mancoosi.mancoosimm.File;
import it.univaq.mancoosi.mancoosimm.Module;
import it.univaq.mancoosi.mancoosimm.ModuleCache;

public class UbuntuModuleCacheManager extends ModuleCacheManager {
	
	protected boolean syncronizeMode = false;
	
	public UbuntuModuleCacheManager(){
		super();
	}

	public static ModuleCacheManager getInstance() {
		if (INSTANCE == null)
			INSTANCE = new UbuntuModuleCacheManager();
		return INSTANCE;
	}
	
	@Override
	public void createModuleCachesFromSystem() {
		ArrayList<ModuleCache> moduleCacheList = new ArrayList<ModuleCache>(); 
		syncMap();
		if(UbuntuEnvironmentManager.getInstance().getEnvironment().getModuleCache() != null){
			moduleCacheList.addAll(UbuntuEnvironmentManager.getInstance().getEnvironment().getModuleCache());
		}
		
		ModuleCache newModuleCache;
		String line;

		try {
			String[] cmd = {"/bin/sh","-c","ls --time-style=long-iso /lib/modules"};
//			String[] cmd = {"/bin/sh","-c","ls --time-style=long-iso /home/martina/mod"};
			BufferedReader input = ProcessCommand.getInstance().getResult(cmd);	

			while ((line = input.readLine()) != null) {
				
				java.io.File file = new java.io.File("/lib/modules/"+line);
//				java.io.File file = new java.io.File("/home/martina/mod/"+line);
				
				if(file.exists()){
					UbuntuFileSystemManager.getInstance().createFile(file.getPath());
					if (!existsModuleCache(line)) {
						newModuleCache = factory.createModuleCache();
						newModuleCache.setVersion(line);
						syncronizeMode = false;
						setModules(newModuleCache, file);
						
						newModuleCache.setEnv(UbuntuEnvironmentManager.getInstance().getEnvironment());
						moduleCacheList.add(newModuleCache);
						this.moduleCacheMap.put(line, newModuleCache);
					}
				}
			}
			UbuntuEnvironmentManager.getInstance().getEnvironment().getModuleCache().addAll(moduleCacheList);
			input.close();

		} catch (Exception err) {
			err.printStackTrace();
		}
	}
	
	protected void setModules(ModuleCache newModuleCache, java.io.File file){
		ArrayList<Module> moduleList = new ArrayList<Module>(); 
		if(syncronizeMode){
			if(UbuntuEnvironmentManager.getInstance().getEnvironment().getModuleCache() != null){			
				int indexMc = UbuntuEnvironmentManager.getInstance().getEnvironment().getModuleCache().indexOf(newModuleCache);
				ModuleCache mc = UbuntuEnvironmentManager.getInstance().getEnvironment().getModuleCache().get(indexMc);
				moduleList.addAll(mc.getModules());
			}
		}
		
		Module newModule;
		String line;

		try {
			String[] cmd = {"/bin/sh","-c","ls --time-style=long-iso " + file.getPath()};
			BufferedReader input = ProcessCommand.getInstance().getResult(cmd);	

			while ((line = input.readLine()) != null) {
				
				java.io.File moduleFile = new java.io.File(file.getPath() + "/" + line);
				
				if(moduleFile.exists() && !moduleFile.isDirectory()){
					File ModuleModelFile = UbuntuFileSystemManager.getInstance()
					.createFile(moduleFile.getPath());
					
					if (!existsModule(line, newModuleCache.getVersion())) {
						newModule = factory.createModule();
						newModule.setName(line);
						newModule.setFile(ModuleModelFile);
						newModule.setModuleCache(newModuleCache);
						moduleList.add(newModule);
						this.moduleMap.put(line+"+"+newModuleCache.getVersion(), newModule);
					}
				}
			}
			newModuleCache.getModules().addAll(moduleList);
			newModuleCache.setEnv(UbuntuEnvironmentManager.getInstance().getEnvironment());
			input.close();

		} catch (Exception err) {
			err.printStackTrace();
		}
	}
	
	
//	public int countModuleCaches() throws IOException {
//		String line;
//
//		Process p;
//		BufferedReader input;
//		int n = 0;
//		try {
////			String[] cmd = {"/bin/sh","-c","ls --time-style=long-iso /lib/modules | wc | awk '{print $1}'"};
//			String[] cmd = {"/bin/sh","-c","ls --time-style=long-iso /home/martina/mod | wc | awk '{print $1}'"};
//			p = Runtime.getRuntime().exec(cmd);
//			input = new BufferedReader
//			(new InputStreamReader(p.getInputStream()));
//			
//			line = input.readLine();
//			
//			n = Integer.parseInt (line);
//
//		input.close();			
//		p.destroy();
//		
//		} catch (NumberFormatException e) {
//			e.printStackTrace();
//		}
//		
//		return n;
//	}

	@Override
	public void synchronize() throws IOException {
		createModuleCachesFromSystem();
		Iterator<ModuleCache> cacheIterator = this.moduleCacheMap.values().iterator();
		while (cacheIterator.hasNext()) {
			ModuleCache curr = cacheIterator.next();
			if (isMissingModuleCacheInTheSystem(curr.getVersion())) {
				this.moduleCacheMap.remove(curr);
				EcoreUtil.delete(curr);
				EList<Module> modules = curr.getModules();
				for(int j=0; j<modules.size(); j++){
					UbuntuFileSystemManager.getInstance().deleteFile(modules.get(j).getFile());
				}
			}else{
				//update modules list for this cache
				java.io.File moduleCacheFile = new java.io.File("/lib/modules/"+curr.getVersion());
//				java.io.File moduleCacheFile = new java.io.File("/home/martina/mod/"+curr.getVersion());
				syncronizeMode = true;
				setModules(curr, moduleCacheFile);
				
				Iterator<Module> moduleIterator = this.moduleMap.values().iterator();

				while (moduleIterator.hasNext()) {
					Module currMod = moduleIterator.next();
					if((currMod.getFile().getLocation()).contains(curr.getVersion())){
						if (isMissingModuleInTheSystem(currMod.getName(), curr.getVersion())) {						
							this.moduleMap.remove(currMod);						
							EcoreUtil.delete(currMod);
							UbuntuFileSystemManager.getInstance().deleteFile("/lib/modules/" + curr.getVersion() +"/" + currMod.getName());
//							UbuntuFileSystemManager.getInstance().deleteFile("/home/martina/mod/" + curr.getVersion() +"/" + currMod.getName());
						}
					}
				}				
			}
		}
	}
	
	public boolean isMissingModuleInTheSystem (String moduleName, String moduleCacheVersion) {
		if(UbuntuFileSystemManager.getInstance().getFile("/lib/modules/"+moduleCacheVersion+"/"+moduleName) != null){
			return UbuntuFileSystemManager.getInstance().getFile("/lib/modules/"+moduleCacheVersion+"/"+moduleName).isIsMissing();
		}else{
			return true;
		}
		
	}
	
	public boolean isMissingModuleCacheInTheSystem (String moduleCacheVersion) {	
		if(UbuntuFileSystemManager.getInstance().getFile("/lib/modules/"+moduleCacheVersion) != null){
			return UbuntuFileSystemManager.getInstance().getFile("/lib/modules/"+moduleCacheVersion).isIsMissing();
		}else{
			return true;
		}
		
	}

	@Override
	public Boolean existsModule(String moduleName, String moduleCacheVersion) {
		return this.moduleMap.containsKey(moduleName +"+"+ moduleCacheVersion);
	}

	@Override
	public Boolean existsModuleCache(String moduleCacheVersion) {
		return this.moduleCacheMap.containsKey(moduleCacheVersion);
	}

}
